Skip to content

Add ProcessStartOptions class with simplified path resolution#124271

Open
Copilot wants to merge 28 commits intomainfrom
copilot/add-processstartoptions-class
Open

Add ProcessStartOptions class with simplified path resolution#124271
Copilot wants to merge 28 commits intomainfrom
copilot/add-processstartoptions-class

Conversation

Copy link
Contributor

Copilot AI commented Feb 11, 2026

Description

Adds ProcessStartOptions class providing explicit, simplified path resolution for process creation. Addresses security and predictability concerns with automatic directory probing.

Changes

API Surface

  • ProcessStartOptions(string fileName) - constructor resolves and validates executable paths
  • Properties: FileName, Arguments, Environment, WorkingDirectory, InheritedHandles, KillOnParentExit, CreateNewProcessGroup
  • Lazy-allocated collections (Arguments, Environment, InheritedHandles)
  • Environment populated from Environment.GetEnvironmentVariables() as Dictionary<string, string?>

Path Resolution Behavior

  • Windows: System32 directory → PATH. Current directory requires explicit .\ prefix.
  • Unix: PATH only. Current directory requires explicit ./ prefix.
  • Fully qualified paths (e.g., C:\path\file.exe) returned as-is
  • Rooted non-qualified paths (e.g., C:file.exe) normalized via Path.GetFullPath
  • Windows: .exe appended when filename lacks extension and path separators
  • Throws FileNotFoundException with localized message when resolution fails

Implementation Details

  • Reuses Environment.SystemDirectory instead of P/Invoke
  • Made Process.IsExecutable internal for shared use
  • Process.Unix retains original ResolvePath/FindProgramInPath for backward compatibility
  • ProcessStartOptions uses new simplified resolution

Tests

  • 25 tests across 3 partial class files (base, Windows, Unix)
  • Theory-based tests for CWD resolution (positive: .\file, negative: file)
  • Platform-conditional tests (IsNotWindowsNanoServer, IsNotWindowsServerCore)
  • Path assertions use EndsWith and Path.GetFullPath() for cross-platform robustness

Example

// Resolves from PATH or System32
var options = new ProcessStartOptions("cmd");
Console.WriteLine(options.FileName); // C:\Windows\System32\cmd.exe

// Explicit current directory reference required
var local = new ProcessStartOptions(@".\myapp.exe");

// Lazy collections
options.Arguments.Add("/c");
options.Arguments.Add("echo test");
options.Environment["VAR"] = "value";

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/area-system-diagnostics-process
See info in area-owners.md if you want to be subscribed.

Copilot AI and others added 3 commits February 11, 2026 14:07
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI changed the title [WIP] Add ProcessStartOptions class to System.Diagnostics namespace Add ProcessStartOptions class with platform-aware path resolution Feb 11, 2026
Copilot AI requested a review from adamsitnik February 11, 2026 14:16
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address my feedback

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot address my feedback

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot please address my feedback

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI requested a review from adamsitnik February 11, 2026 18:49
- add comments
- cache Environment.SystemDirectory
- handle fully qualified paths on Windows
@stephentoub
Copy link
Member

@copilot invoke the code-review skill and post your analysis/results as a comment on this pr

// "Applications should not under any circumstances pass user-controlled input directly to CreateProcess;
// or, if they intend to do so (for passing user-originated parameters), they should be filling out the lpApplicationName parameter."
//
// We could either document that the FileName should never be user-controlled input or resolve it ourselves,
Copy link
Member

@jkotas jkotas Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this point. If we wanted to leave resolution of the file name to the OS, we could add the quotation marks around the file name as the official documentation suggests.

I think the main problem with leaving the resolution to the OS is that it would not work well with the current public API shape. We would not be able to provide the resolved path before the process starts as a public OS neutral API.

So I think the reasoning should be as follows:

  • We want to provide resolved path API
  • It means we need to have our own copy of the path resolution algorithm since there is no Windows OS API to do that.
  • Our own copy of the path resolution algorithm is not going to be equivalent to the Windows OS provided one since it is not fully documented.
  • We take it as an opportunity to clean up the legacy baggage to have simpler, easier to understand and more secure filename resolution algorithm that is consistent across OSes and aligned with other modern platforms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand this point. If we wanted to leave resolution of the file name to the OS, we could add the quotation marks around the file name as the official documentation suggests.

This was also my understanding, but the feedback I got from the Windows Team made me believe we should not be doing this.

  • We take it as an opportunity to clean up the legacy baggage to have simpler, easier to understand and more secure filename resolution algorithm that is consistent across OSes and aligned with other modern platforms.

I agree it's great opportunity and timing (Preview 2?). However, which parts exactly do we want to give up on?

no current directory probing

For CWD, we could just explicitly demand the ".\here.exe" syntax.

no process .exe path probing

It's a valid scenario, but the users can use Path.Combine(Path.GetDirectoryName(Environment.ProcessPath), "name") API to build such path quickly (assuming Environment.ProcessPath does not return null).

no legacy Windows directory probing, etc.

Just to be sure, by legacy you don't mean C:\Windows\System32 (returned by Environment.ProcessPath, contains "cmd.exe" etc), but C:\Windows\System?

@stephentoub
Copy link
Member

@copilot?

Copy link
Member

@adamsitnik adamsitnik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot Please address my feedback

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
auto-merge was automatically disabled February 16, 2026 08:32

Head branch was pushed to by a user without write access

Copilot AI requested a review from adamsitnik February 16, 2026 08:34
@adamsitnik
Copy link
Member

@copilot address all of my feedback, not only some parts of it

Copilot AI and others added 2 commits February 16, 2026 10:43
… explicit ./

Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Co-authored-by: adamsitnik <6011991+adamsitnik@users.noreply.github.com>
Copilot AI changed the title Add ProcessStartOptions class with platform-aware path resolution Add ProcessStartOptions class with simplified path resolution Feb 16, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 12 changed files in this pull request and generated 2 comments.

Comment on lines +247 to +253
if (path != null)
{
path = Path.Combine(path, filename);
if (File.Exists(path))
{
return path;
}
Copy link

Copilot AI Feb 16, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Environment.SystemDirectory is a non-nullable string property that always returns a value. The null check on line 247 is unnecessary and violates the coding guideline to trust C# null annotations and avoid null checks when the type system indicates a value cannot be null.

Suggested change
if (path != null)
{
path = Path.Combine(path, filename);
if (File.Exists(path))
{
return path;
}
path = Path.Combine(path, filename);
if (File.Exists(path))
{
return path;

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants